/*
 * Copyright 2010 Biz-e (info@biz-e.nl)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.biz_e.gwt.baselib.ui.client.widgets;

import java.util.Date;

import nl.biz_e.gwt.baselib.ui.client.windows.MessageBox;

import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.datepicker.client.CalendarUtil;
import com.google.gwt.user.datepicker.client.DatePicker;

/**
 * @author Joost A. Bloemsma
 * 
 */
public class DateField extends Composite implements DoubleClickHandler,
		HasValueChangeHandlers<Date> {
	
	private class StringValueChangeHandler implements ValueChangeHandler<String> {
		private final DateField field;
		
		/**
		 * Constructs a new DateValueChangeHandler instance
		 * 
		 * @param field
		 */
		StringValueChangeHandler(DateField field) {
			super();
			this.field = field;
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onValueChange(ValueChangeEvent<String> event) {
			field.onValueChanged(event.getValue());
		}
		
	}
	
	private class DateValueChangeHandler implements ValueChangeHandler<Date> {
		private final DateField field;
		
		/**
		 * Constructs a new DateValueChangeHandler instance
		 * 
		 * @param field
		 */
		DateValueChangeHandler(DateField field) {
			super();
			this.field = field;
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onValueChange(ValueChangeEvent<Date> event) {
			field.onValueChanged(event.getValue());
		}
		
	}
	
	private final DatePicker datePicker = new DatePicker();
	private final DCTextBox dateBox = new DCTextBox();
	private final DateValueChangeHandler datePickerHandler;
	private final StringValueChangeHandler dateBoxHandler;
	private boolean openOnDblClick = true;
	private DateTimeFormat dateFormat = DateTimeFormat.getFormat("dd-MM-yyyy");
	private Date date;
	
	/**
	 * Constructs a new DateField instance
	 */
	public DateField() {
		super();
		
		datePickerHandler = new DateValueChangeHandler(this);
		datePicker.addValueChangeHandler(datePickerHandler);
		
		dateBoxHandler = new StringValueChangeHandler(this);
		dateBox.addDoubleClickHandler(this);
		dateBox.addValueChangeHandler(dateBoxHandler);
		
		this.initWidget(dateBox);
		
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onDoubleClick(DoubleClickEvent event) {
		if (openOnDblClick) this.showCalendar();
	}
	
	/**
	 * Shows the popup calendar
	 */
	public void showCalendar() {
		if (this.date != null) {
			datePicker.setValue(this.date, false);
			datePicker.setCurrentMonth(this.date);
		}
		PopupPanel popupPanel = new PopupPanel(true);
		popupPanel.add(datePicker);
		int left = this.getAbsoluteLeft() + this.getOffsetWidth();
		int top = this.getAbsoluteTop();
		popupPanel.setPopupPosition(left, top);
		popupPanel.show();
	}
	
	/**
	 * If set to true (default), a double click on the field will open
	 * the popup calendar
	 * 
	 * @param bool
	 */
	public void openOnDoubleClick(boolean bool) {
		this.openOnDblClick = bool;
	}
	
	/**
	 * @param date
	 */
	public void setValue(Date date) {
		this.setValue(date, false);
	}
	
	/**
	 * Set a new value in the datefield.
	 * 
	 * @param date
	 * @param fireEvents should events be fired.
	 */
	public void setValue(Date date, boolean fireEvents) {
		this.setDateValue(date, fireEvents);
		dateBox.setValue(dateFormat.format(date), false);
	}
	
	/**
	 * @return The current date value
	 */
	public Date getValue() {
		return (Date) this.date.clone();
	}
	
	private void setDateValue(Date date, boolean fireEvents) {
		Date oldValue = CalendarUtil.copyDate(this.date);
		this.date = CalendarUtil.copyDate(date);
		if (fireEvents) {
			DateChangeEvent.fireIfNotEqualDates(this, oldValue, date);
		}
	}
	
	private void onValueChanged(Date value) {
		setDateValue(value, true);
		dateBox.setValue(dateFormat.format(date), false);
	}
	
	private void onValueChanged(String value) {
		try {
			Date val = dateFormat.parse(value);
			this.date = val;
		} catch (IllegalArgumentException e) {
			new MessageBox("Not a valid date").show();
			dateBox.setValue(dateFormat.format(date), false);
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Date> handler) {
		return addHandler(handler, ValueChangeEvent.getType());
	}
}
